package com.clw.runtime;

import com.clw.runtime.heap.ClassLoader;
import com.clw.runtime.heap.MethodArea.Field;
import com.clw.runtime.heap.MethodArea.Method;
import com.clw.runtime.heap.MethodArea.RuntimeConstantPool;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;

/**
 * Created by chengliwei on 2019/1/13.
 */
public class Class {

    private int accessFlags;
    private String thisClassName;
    private String superClassName;
    private String[] interfaceNames;
    private RuntimeConstantPool constantPool;
    private Field[] fields;
    private Method[] methods;
    private ClassLoader classLoader;
    private Class superClass;
    private Class[] interfaceClasses;
    private int instanceCount;
    private int staticCount;
    private int[] staticVars;

    public Class(ClassFile classFile) throws ConstantPoolException {
        this.accessFlags = classFile.access_flags.flags;
        this.thisClassName = classFile.getName();
        if (!getThisClassName().equals("java/lang/Object")) {
            this.superClassName = classFile.getSuperclassName();
        }

        int[] interfaceIndices = classFile.interfaces;
        this.interfaceNames = new String[interfaceIndices.length];
        for (int i = 0; i < interfaceIndices.length; i++) {
            interfaceNames[i] = classFile.getInterfaceName(i);
        }

        this.constantPool = new RuntimeConstantPool(classFile.constant_pool, this);

        ConstantPool classConstantPool = classFile.constant_pool;
        int fieldsCount = classFile.fields.length;
        this.fields = new Field[fieldsCount];
        for (int i = 0; i < fieldsCount; i++) {
            com.sun.tools.classfile.Field field = classFile.fields[i];
            fields[i] = new Field(field.access_flags.flags,
                    field.getName(classConstantPool),
                    field.descriptor.getValue(classConstantPool),
                    this);
        }
        int methodsCount = classFile.methods.length;
        this.methods = new Method[methodsCount];
        for (int i = 0; i < methodsCount; i++) {
            com.sun.tools.classfile.Method method = classFile.methods[i];
            Code_attribute codeAttribute = (Code_attribute) method.attributes.get("Code");
            if (codeAttribute == null) {
                methods[i] = null;
            } else {
                methods[i] = new Method(method.access_flags.flags,
                        method.getName(classConstantPool),
                        method.descriptor.getValue(classConstantPool),
                        this,
                        codeAttribute.max_locals,
                        codeAttribute.max_stack,
                        codeAttribute.code);
            }
        }
    }

    public int getAccessFlags() {
        return accessFlags;
    }

    public void setAccessFlags(int accessFlags) {
        this.accessFlags = accessFlags;
    }

    public String getThisClassName() {
        return thisClassName;
    }

    public void setThisClassName(String thisClassName) {
        this.thisClassName = thisClassName;
    }

    public String getSuperClassName() {
        return superClassName;
    }

    public void setSuperClassName(String superClassName) {
        this.superClassName = superClassName;
    }

    public String[] getInterfaceNames() {
        return interfaceNames;
    }

    public void setInterfaceNames(String[] interfaceNames) {
        this.interfaceNames = interfaceNames;
    }

    public RuntimeConstantPool getConstantPool() {
        return constantPool;
    }

    public void setConstantPool(RuntimeConstantPool constantPool) {
        this.constantPool = constantPool;
    }

    public Field[] getFields() {
        return fields;
    }

    public void setFields(Field[] fields) {
        this.fields = fields;
    }

    public Method[] getMethods() {
        return methods;
    }

    public void setMethods(Method[] methods) {
        this.methods = methods;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Class getSuperClass() {
        return superClass;
    }

    public void setSuperClass(Class superClass) {
        this.superClass = superClass;
    }

    public Class[] getInterfaceClasses() {
        return interfaceClasses;
    }

    public void setInterfaceClasses(Class[] interfaceClasses) {
        this.interfaceClasses = interfaceClasses;
    }

    public int getInstanceCount() {
        return instanceCount;
    }

    public void setInstanceCount(int instanceCount) {
        this.instanceCount = instanceCount;
    }

    public int getStaticCount() {
        return staticCount;
    }

    public void setStaticCount(int staticCount) {
        this.staticCount = staticCount;
    }

    public int[] getStaticVars() {
        return staticVars;
    }

    public void setStaticVars(int[] staticVars) {
        this.staticVars = staticVars;
    }
}
